package engine.render.type;

import engine.render.GLManager;
import engine.res.Bitmap;
import engine.res.Color;
import math.Maths;
import math.vector.Vecmath;
import math.vector.vec2f;
import math.vector.vec3f;
import static engine.GL.*;

public class Tri 
{

    public static final int nVerts = 3;
    public vec3f[] verts;
    public vec2f[] texs;
    public vec3f norm;
    public Bitmap tex;
    public Color modifier;
    
    public vec3f barycenter;

    public Tri() 
    {
        verts = new vec3f[nVerts];
        texs = new vec2f[nVerts];
        for (int i = 0; i < nVerts; i++) 
        {
            verts[i] = new vec3f();
            texs[i] = new vec2f();
        }
        modifier = Color.WHITE;
        barycenter = new vec3f();
    }
    
    public Tri(
            float x0, float y0, float z0, float s0, float t0, 
            float x1, float y1, float z1, float s1, float t1, 
            float x2, float y2, float z2, float s2, float t2)
    {
        this();
        verts[0] = new vec3f(x0, y0, z0);
        verts[1] = new vec3f(x1, y1, z1);
        verts[2] = new vec3f(x2, y2, z2);
        texs[0] = new vec2f(s0, t0);
        texs[1] = new vec2f(s1, t1);
        texs[2] = new vec2f(s2, t2);
        barycenter.x = (x0 + x1 + x2) * Maths.ONE_OVER_3;
        barycenter.y = (y0 + y1 + y2) * Maths.ONE_OVER_3;
        barycenter.z = (z0 + z1 + z2) * Maths.ONE_OVER_3;
    }
    
    public Tri(
            vec3f v0, float s0, float t0, 
            vec3f v1, float s1, float t1, 
            vec3f v2, float s2, float t2)
    {
        this(
            v0.x, v0.y, v0.z, s0, t0, 
            v1.x, v1.y, v1.z, s1, t1, 
            v2.x, v2.y, v2.z, s2, t2
        );
    }
    
    public Tri(
            vec3f v0, vec2f tc0, 
            vec3f v1, vec2f tc1, 
            vec3f v2, vec2f tc2)
    {
        this(
            v0.x, v0.y, v0.z, tc0.x, tc0.y, 
            v1.x, v1.y, v1.z, tc1.x, tc1.y, 
            v2.x, v2.y, v2.z, tc2.x, tc2.y
        );
    }

    public Tri(vec3f[] vertices, vec2f[] texCoords) 
    {
        this(
            vertices[0], texCoords[0], 
            vertices[1], texCoords[1], 
            vertices[2], texCoords[2]
        );
    }
    
    public Tri(Tri tri) 
    {
        this(tri.verts, tri.texs);
        norm = new vec3f(tri.norm);
        tex = tri.tex;
        modifier = tri.modifier;
        barycenter = tri.barycenter;
    }
    
    public boolean onNormalSide(vec3f v) 
    {
        float dotProd = Vecmath.dotProduct(norm, v);
        return (dotProd >= 0);
    }
    
    public void colorModifier(Color mod) 
    {
        modifier = mod;
    }
    
    public void texture(Bitmap texture) 
    {
        tex = texture;
    }

    public void normalCalc() 
    {
        norm = Vecmath.getSurfaceNormal(verts[0], verts[1], verts[2]);
    }
    
    public void normal(vec3f normal) 
    {
        norm = normal;
    }

    public void normal(float nx, float ny, float nz) 
    {
        normal(new vec3f(nx, ny, nz));
    }

    public void normal(double nx, double ny, double nz) 
    {
        normal(new vec3f(nx, ny, nz));
    }

    public void vertex(int index, float vx, float vy, float vz) 
    {
        vertex(index, new vec3f(vx, vy, vz));
    }
    
    public void vertex(int index, double vx, double vy, double vz) 
    {
        vertex(index, (float)vx, (float)vy, (float)vz);
    }
    
    public void vertex(int index, vec3f vert) 
    {
        verts[index] = vert;
    }

    public void texCoord(int index, float s, float t) 
    {
        texCoord(index, new vec2f(s, t));
    }
    
    public void texCoord(int index, double s, double t) 
    {
        texCoord(index, new vec2f(s, t));
    }
    
    public void texCoord(int index, vec2f texCoord) 
    {
        texs[index] = texCoord;
    }
    
    public void rotateDeg(float pitch, float yaw, float roll, float xpos, float ypos, float zpos) 
    {
        float rollRad = Maths.toRadians(roll);
        float yawRad = Maths.toRadians(yaw);
        float pitchRad = Maths.toRadians(pitch);
        rotateRad(pitchRad, yawRad, rollRad, xpos, ypos, zpos);
    }
    
    public void rotateDeg(vec3f anglesDeg, float xpos, float ypos, float zpos) 
    {
        rotateDeg(anglesDeg.x, anglesDeg.y, anglesDeg.z, xpos, ypos, zpos);
    }
    
    public void rotateRad(float pitch, float yaw, float roll, float xpos, float ypos, float zpos) 
    {
        vec3f trans = new vec3f(xpos, ypos, zpos);
        vec3f transInvert = trans.getInverted();
        for (int i=0; i < verts.length; i++) 
        {
            vec3f vert = Vecmath.add(verts[i], transInvert);
            if (roll != 0)
                vert = Vecmath.rotate(vert, 0, 0, 1, roll);
            if (yaw != 0)
                vert = Vecmath.rotate(vert, 0, 1, 0, yaw);
            if (pitch != 0)
                vert = Vecmath.rotate(vert, 1, 0, 0, pitch);
            verts[i] = Vecmath.add(vert, trans);
        }
        vec3f vert = Vecmath.add(norm, transInvert);
        vert = Vecmath.rotate(vert, 0, 0, 1, roll);
        vert = Vecmath.rotate(vert, 0, 1, 0, yaw);
        vert = Vecmath.rotate(vert, 1, 0, 0, pitch);
        norm = Vecmath.add(vert, trans);
    }
    
    public void rotateRad(vec3f anglesRad, float xpos, float ypos, float zpos) 
    {
        rotateRad(anglesRad.x, anglesRad.y, anglesRad.z, xpos, ypos, zpos);
    }
    
    public void translate(float dx, float dy, float dz) 
    {
        verts[0].add(dx, dy, dz);
        verts[1].add(dx, dy, dz);
        verts[2].add(dx, dy, dz);
    }
    
    public void translate(vec3f translate) 
    {
        verts[0].add(translate.x, translate.y, translate.z);
        verts[1].add(translate.x, translate.y, translate.z);
        verts[2].add(translate.x, translate.y, translate.z);
    }
    
    public String toString() 
    {
        String s = "";
        for (int i = 0; i < nVerts; i++) 
        {
            s += "TRIANGLE";
            s += "   xyz: " + verts[i].toString() + "\n";
            s += "   st: " + texs[i].toString() + "\n";
            s += "   norm: " + norm.toString() + "\n";
            s += "   tex: " + tex + "\n";
        }
        return s;
    }

    public void render(GLManager glManager) 
    {
        glManager.bindColor(modifier);
        glManager.bindBitmap(tex);
        norm(norm);
        begin(TRIANGLE_STRIP);
        
        tex(texs[0]);
        vert(verts[0]);
        tex(texs[1]);
        vert(verts[1]);
        tex(texs[2]);
        vert(verts[2]);
        
        end();
    }

}
